#include "dialog_setup_scene.h"
#include "ui_dialog_setup_scene.h"
#include "../Program.h"
#include "../entity/EntityLight.h"
#include "../entity/EntityCamera.h"
#include "../utility/Common.h"
#include "../AvatarLibrary.h"
#define SLIDER_VALUE(x) static_cast<int>(x * 180.0f / 3.14159f)

DialogSetupScene::DialogSetupScene(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::DialogSetupScene)
{
    ui->setupUi(this);
    QDoubleValidator* val = new QDoubleValidator(this);
    val->setDecimals(3);
    val->setNotation(QDoubleValidator::StandardNotation);
    ui->lineEditLightPosX->setValidator(val);
    ui->lineEditLightPosY->setValidator(val);
    ui->lineEditLightPosZ->setValidator(val);
    ui->lineEditLightRange->setValidator(val);
    ui->lineEditCameraClipNear->setValidator(val);
    ui->lineEditCameraClipFar->setValidator(val);
    connect(ui->radioButtonLightDirectional, &QRadioButton::toggled, this, &DialogSetupScene::radioButtonLight_toggled);
    connect(ui->radioButtonLightPoint, &QRadioButton::toggled, this, &DialogSetupScene::radioButtonLight_toggled);
    connect(ui->radioButtonLightSpot, &QRadioButton::toggled, this, &DialogSetupScene::radioButtonLight_toggled);
    connect(ui->lineEditLightPosX, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditLight_editingFinished);
    connect(ui->lineEditLightPosY, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditLight_editingFinished);
    connect(ui->lineEditLightPosZ, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditLight_editingFinished);
    connect(ui->lineEditLightRange, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditLight_editingFinished);
    connect(ui->lineEditLightColor, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditLight_editingFinished);
    connect(ui->sliderLightDirYaw, &QSlider::actionTriggered, this, &DialogSetupScene::slider_actionTriggered);
    connect(ui->sliderLightDirPitch, &QSlider::actionTriggered, this, &DialogSetupScene::slider_actionTriggered);
    connect(ui->sliderLightAngle, &QSlider::actionTriggered, this, &DialogSetupScene::slider_actionTriggered);
    connect(ui->checkBoxLightBind, &QCheckBox::checkStateChanged, this, [&]() {
        Program::LightParam.BindCamera = ui->checkBoxLightBind->isChecked();
        AvatarLibrary::avatar_command(Program::LightParam.Script());
    });
    connect(ui->lineEditCameraClipNear, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditCamera_editingFinished);
    connect(ui->lineEditCameraClipFar, &QLineEdit::editingFinished, this, &DialogSetupScene::lineEditCamera_editingFinished);
    connect(ui->spinBoxCameraFov, &QSpinBox::valueChanged, this, [&](int value) {
        Program::CameraParam.FieldOfView = value;
        AvatarLibrary::avatar_command(QString("camera.fov(%1)").arg(Program::CameraParam.FieldOfView));
    });
    ui->checkBoxLightBind->setChecked(Program::LightParam.BindCamera);
    ui->lineEditLightColor->setValue(Common::ConvertColor(Program::LightParam.Color));
    if (Program::LightParam.Type == EntityLight::LightType::DIRECTIONAL)ui->radioButtonLightDirectional->setChecked(true);
    else if (Program::LightParam.Type == EntityLight::LightType::POINT)ui->radioButtonLightPoint->setChecked(true);
    else if (Program::LightParam.Type == EntityLight::LightType::SPOT) ui->radioButtonLightSpot->setChecked(true);
    // 相机参数
    ui->spinBoxCameraFov->setValue(Program::CameraParam.FieldOfView);
    ui->lineEditCameraClipNear->setText(QString::number(Program::CameraParam.ClipNear));
    ui->lineEditCameraClipFar->setText(QString::number(Program::CameraParam.ClipFar));
}

DialogSetupScene::~DialogSetupScene()
{
    delete ui;
}

void DialogSetupScene::radioButtonLight_toggled(bool checked) {
    if (checked) {
        QRadioButton* radioButton = (QRadioButton*)sender();
        if (radioButton == ui->radioButtonLightDirectional) Program::LightParam.Type = EntityLight::LightType::DIRECTIONAL;
        else if (radioButton == ui->radioButtonLightPoint) Program::LightParam.Type = EntityLight::LightType::POINT;
        else if (radioButton == ui->radioButtonLightSpot) Program::LightParam.Type = EntityLight::LightType::SPOT;
        QVector3D dir = Program::LightParam.Direction;
        switch (Program::LightParam.Type)
        {
        case EntityLight::LightType::DIRECTIONAL:
            ui->groupBoxLightPos->hide();
            ui->groupBoxLightDir->show();
            ui->labelLightRange->hide();
            ui->lineEditLightRange->hide();
            ui->labelLightAngle->hide();
            ui->sliderLightAngle->hide();
            ui->sliderLightDirYaw->setValue(SLIDER_VALUE(atan2f(dir.y(), dir.x())));
            ui->sliderLightDirPitch->setValue(SLIDER_VALUE(atan2f(dir.z(), sqrtf(dir.y()*dir.y() + dir.x()*dir.x()))));
            break;
        case EntityLight::LightType::POINT:
            ui->groupBoxLightPos->show();
            ui->groupBoxLightDir->hide();
            ui->labelLightRange->show();
            ui->lineEditLightRange->show();
            ui->labelLightAngle->hide();
            ui->sliderLightAngle->hide();
            ui->lineEditLightPosX->setText(QString::number(Program::LightParam.Position.x()));
            ui->lineEditLightPosY->setText(QString::number(Program::LightParam.Position.y()));
            ui->lineEditLightPosZ->setText(QString::number(Program::LightParam.Position.z()));
            ui->lineEditLightRange->setText(QString::number(Program::LightParam.Range));
            break;
        case EntityLight::LightType::SPOT:
            ui->groupBoxLightPos->show();
            ui->groupBoxLightDir->show();
            ui->labelLightRange->show();
            ui->lineEditLightRange->show();
            ui->labelLightAngle->show();
            ui->sliderLightAngle->show();
            ui->lineEditLightPosX->setText(QString::number(Program::LightParam.Position.x()));
            ui->lineEditLightPosY->setText(QString::number(Program::LightParam.Position.y()));
            ui->lineEditLightPosZ->setText(QString::number(Program::LightParam.Position.z()));
            ui->lineEditLightRange->setText(QString::number(Program::LightParam.Range));
            ui->sliderLightAngle->setValue(SLIDER_VALUE(Program::LightParam.Angle));
            ui->sliderLightDirYaw->setValue(SLIDER_VALUE(atan2f(dir.y(), dir.x())));
            ui->sliderLightDirPitch->setValue(SLIDER_VALUE(atan2f(dir.z(), sqrtf(dir.y()*dir.y() + dir.x()*dir.x()))));
            break;
        }
        AvatarLibrary::avatar_command(Program::LightParam.Script());
    }
}

void DialogSetupScene::lineEditLight_editingFinished()
{
    QLineEdit* lineEdit = qobject_cast<QLineEdit*>(sender());
    if (lineEdit == ui->lineEditLightPosX) Program::LightParam.Position.setX(lineEdit->text().toFloat());
    else if (lineEdit == ui->lineEditLightPosY) Program::LightParam.Position.setY(lineEdit->text().toFloat());
    else if (lineEdit == ui->lineEditLightPosZ) Program::LightParam.Position.setZ(lineEdit->text().toFloat());
    else if (lineEdit == ui->lineEditLightRange) Program::LightParam.Range = lineEdit->text().toFloat();
    else if (lineEdit == ui->lineEditLightColor) Program::LightParam.Color = Common::ConvertColor(lineEdit->text());
    AvatarLibrary::avatar_command(Program::LightParam.Script());
}

void DialogSetupScene::lineEditCamera_editingFinished()
{
    QLineEdit* lineEdit = qobject_cast<QLineEdit*>(sender());
    if (lineEdit == ui->lineEditCameraClipNear) Program::CameraParam.ClipNear = lineEdit->text().toFloat();
    else if (lineEdit == ui->lineEditCameraClipFar) Program::CameraParam.ClipFar = lineEdit->text().toFloat();
    AvatarLibrary::avatar_command(QString("camera.clip(%1,%2)").arg(Program::CameraParam.ClipNear).arg(Program::CameraParam.ClipFar));
}

void DialogSetupScene::slider_actionTriggered(int action)
{
    QSlider* slider = qobject_cast<QSlider*>(sender());
    if (slider == ui->sliderLightDirYaw || slider == ui->sliderLightDirPitch)
    {
        float yaw = ui->sliderLightDirYaw->sliderPosition() * 3.14159f / 180.0f;
        float pitch = ui->sliderLightDirPitch->sliderPosition() * 3.14159f / 180.0f;
        Program::LightParam.Direction.setX(cosf(pitch) * cosf(yaw));
        Program::LightParam.Direction.setY(cosf(pitch) * sinf(yaw));
        Program::LightParam.Direction.setZ(sinf(pitch));
    }
    else if (slider == ui->sliderLightAngle) Program::LightParam.Angle = slider->sliderPosition() * 3.14159f / 180.0f;
    AvatarLibrary::avatar_command(Program::LightParam.Script());
}
